﻿using System;
using System.Collections.Generic;
using System.Text;


namespace Magenic.CodeMastery.SharePoint.PMO
{
    public class DisplayPeriod
    {
        /// <summary>
        /// Inclusive
        /// </summary>
        public readonly DateTime FirstDay;

        /// <summary>
        /// Inclusive
        /// </summary>
        public readonly DateTime LastDay;

        public readonly int Months;

        /// <summary>
        /// Current assumption is four (4) fixed quarterly columns per month.
        /// TODO: Revisit with an eye to a week-based column.
        /// </summary>
        private const int columnsPerMonth = 4;

        public int Columns { get { return Months * columnsPerMonth; } }

        public DisplayPeriod(DateTime firstDay, int months)
        {
            const int minMonths = 1;
            const int maxMonths = 16;
            if (months < minMonths || months > maxMonths)
                throw new ArgumentOutOfRangeException("monthsToDisplay",
                    String.Format("{0} does not fall within [{1},{2}]",
                    months, minMonths, maxMonths));
            FirstDay = new DateTime(firstDay.Year, firstDay.Month, 1);
            LastDay = LastDayOfMonth(FirstDay.AddMonths(months - 1));
            this.Months = months;
        }

        /// <summary>
        /// Determines whether some portion of the passed-in project falls within
        /// displayed period.
        /// </summary>
        /// <param name="test"></param>
        /// <returns></returns>
        public Boolean OverlapsWithProject(Project test)
        {
            return (!(test.Finish < FirstDay || test.Start > LastDay));
        }

        /// <summary>
        /// The column index of the passed-in date.
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public int DateToColumn(DateTime date)
        {
            if (date < FirstDay || date > LastDay)
                throw new ArgumentOutOfRangeException("date",
                    String.Format("{0} does not fall within [{1},{2}]",
                    date, FirstDay, LastDay));
            //full months
            int columnIndex = 0;
            DateTime monthEnd = LastDayOfMonth(FirstDay);
            while (date > monthEnd)
            {
                columnIndex += columnsPerMonth;
                monthEnd = LastDayOfMonth(monthEnd.AddDays(1));
            }
            //remainder
            Decimal columns = date.Day * columnsPerMonth;
            columns /= DateTime.DaysInMonth(date.Year, date.Month);
            columns += .49M;
            columns = Math.Round(columns, 0,MidpointRounding.AwayFromZero);
            columnIndex += (int)columns;
            return columnIndex;
        }

        public static DateTime LastDayOfMonth(DateTime anyDay)
        {
            DateTime lastDay = new DateTime(anyDay.Year, anyDay.Month, 1);
            lastDay = lastDay.AddMonths(1).AddDays(-1);
            return lastDay;
        }

        public int StartColumn(Project project)
        {
            DateTime test = project.Start;
            if (test > this.LastDay)
                throw new ArgumentOutOfRangeException("project",
                    "Project starts after end of period.");
            if (test < FirstDay)
                test = FirstDay;
            return DateToColumn(test);
        }

        public int FinishColumn(Project project)
        {
            DateTime test = project.Finish;
            if (test < this.FirstDay)
                throw new ArgumentOutOfRangeException("project",
                    "Project ends before start of period.");
            if (test > LastDay)
                test = LastDay;
            return DateToColumn(test);
        }
    }
}